/////////////////////////////////////////////////////
// File Name: fixed_priority_arbiter.v
// Author: zeping fan
// mail:   zpfan007@163.com
// Created Time: 2023年09月26日 星期二 15时07分38秒
/////////////////////////////////////////////////////

module fixed_priority_arbiter(
clk,
rst_n,
req,
grant,
grant_vld,
grant_ff,
grant_ff_vld,
switch_to_next
);

parameter   REQ_CNT     = 4;

input                       clk;
input                       rst_n;
input   [REQ_CNT-1:0]       req;
input                       switch_to_next;
output  [REQ_CNT-1:0]       grant;
output                      grant_vld;
output  [REQ_CNT-1:0]       grant_ff;
output                      grant_ff_vld;

wire    [REQ_CNT-1:0]       grant;
wire                        grant_vld;
reg     [REQ_CNT-1:0]       grant_ff;
reg                         grant_ff_vld;

wire                        no_req;
wire                        no_grant;
wire                        first_grant;
wire                        arb_trig;

assign no_req       = ~(|req);
assign no_grant     = ~(|grant_ff);
assign first_grant  = ~no_req && no_grant;
assign arb_trig     = first_grant || switch_to_next;

assign grant = arb_trig? (req & (~(req-1'b1))) : 1'b0;
assign grant_vld = (arb_trig && ~no_req)? 1'b1 : 1'b0;


always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        grant_ff <= {REQ_CNT{1'b0}};        
    else if(arb_trig)
        grant_ff <= grant;
    else 
        grant_ff <= grant_ff;
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        grant_ff_vld <= 1'b0;
    else if(arb_trig)
        grant_ff_vld <= no_req? 1'b0 : 1'b1;
end

endmodule






